package com.bone.spider;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import javax.inject.Inject;

import org.apache.commons.io.FileUtils;
import org.springframework.beans.BeansException;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.data.domain.Example;
import org.springframework.stereotype.Component;
import org.springframework.util.DigestUtils;

import com.bone.spider.domain.StorageMata;
import com.bone.spider.enumeration.DownloadStatus;
import com.bone.spider.repository.StorageMataRepository;

import lombok.extern.slf4j.Slf4j;

import static com.bone.spider.service.MainService.SCORE_URL;
import static com.bone.spider.service.MainService.connectURL;

@Slf4j
@Component
public class SpiderApplicationRunner implements ApplicationRunner, ApplicationContextAware {
  
  private static final Pattern jap = Pattern.compile("^[a-zA-Z]+-[\\d]+.*$");

  public static final String DOWNLOAD_DIR = "D:\\安装包\\ART\\test";
  public static final String DOWNLOAD_DIR_CHN = "D:\\安装包\\ART\\chn";
  public static final String DOWNLOAD_DIR_JAP = "D:\\安装包\\ART\\jap";
  public static final String DOWNLOAD_DIR_OTH = "D:\\安装包\\ART\\oth";
  
  @Inject
  private StorageMataRepository storageMataRepository;
  
  private ConfigurableApplicationContext applicationContext;
  
  @Override
  public void run(ApplicationArguments args) throws Exception {
    /*System.err.println("爬取子页面...");
    List<String> allArticle = getAllVideoPage(100);
    System.err.println("爬取视频...");
    Map<String, String> urlMap = getUrlInSource(allArticle);
    List<StorageMata> storageMataList = urlMap.entrySet().stream().map(entry -> {
      StorageMata storageMata = new StorageMata();
      storageMata.setPathName(isJap(entry.getKey()) ? DOWNLOAD_DIR_JAP : DOWNLOAD_DIR);
      storageMata.setDownloadStatus(DownloadStatus.NEW);
      storageMata.setUrl(entry.getValue());
      storageMata.setName(entry.getKey());
      return storageMata;
    }).collect(Collectors.toList());
    storageMataRepository.saveAll(storageMataList);
    applicationContext.close();*/
  }

  public static List<String> getAllVideoPage(int i) throws Exception {
    List<String> urls = new ArrayList<>();
    // 要爬哪些页数
    for (int j = 1; j < i; j++) {
      URL url = new URL(String.format(SCORE_URL, j));
      // 连接url
      try (BufferedReader br = connectURL(url)) {
        String line;
        String videoUrl;
        while ((line = br.readLine()) != null) {
          if (line.contains("item thumb thumb--videos")) {
            videoUrl = br.readLine();
            br.readLine();
            br.readLine();
            br.readLine();
            String rateLine = br.readLine();
            int rate = Integer.parseInt(rateLine.substring(rateLine.indexOf("<span>") + 6, rateLine.indexOf("%")));
            if (rate >= 70) {
              urls.add(videoUrl.substring(videoUrl.indexOf("href=\"") + 6, videoUrl.indexOf("title=") - 2));
            }
          }
        }
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
    return urls;
  }

  public Map<String, String> getUrlInSource(List<String> source) throws IOException {

    Map<String, String> hashMap = new HashMap<>();
    for (int j = 0; j < source.size(); j++) {
      String pageUrl = source.get(j);
      URL url = new URL(pageUrl);
      // 连接url
      try (BufferedReader br = connectURL(url)) {
        String title = null;
        // 此处不要==null进行判断，因为网页中有很多行都是null，否则会报java.lang.NullPointerException?
        for (int i = 0; i < 10000; i++) {
          String info = br.readLine();
          if (null != info) {// 这里截取视频名称，也是根据页面实际情况
            if (info.contains("<title>")) {
              int st = info.indexOf("<title>") + 7;
              int ed = info.lastIndexOf("</title>");
              title = info.substring(st, ed);
              if (exists(title)) {
                break;
              }
            }
            if (info.contains("video_url")) {// 这里截取视频实际下载url，也是根据页面实际情况
              int start = info.indexOf("video_url: '") + 12;
              int end = info.indexOf("mp4") + 3;
              String substring = info.substring(start, end) + "/?download=true";
              hashMap.put(title, substring);
              break;
            }
          }
        }
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
    return hashMap;
  }
  
  private boolean exists(String name) {
    return storageMataRepository.findFirstByName(name + ".mp4") != null;
  }
  
  private void saveStorageMata(String dir) {
    List<StorageMata> storageMataList = FileUtils.listFiles(new File(dir), null, false).stream().map(file -> {
      if (!file.exists() || !file.isFile()) {
        return null;
      }
      String md5;
      try (InputStream is = new FileInputStream(file)) {
        md5 = DigestUtils.md5DigestAsHex(is).toLowerCase();
      } catch (Exception e) {
        return null;
      }
      StorageMata storageMata = new StorageMata();
      storageMata.setMd5(md5);
      boolean exists = storageMataRepository.exists(Example.of(storageMata));
      if (exists) {
        System.out.println("file exists: " + file.getAbsolutePath());
        return null;
      }
      storageMata.setName(file.getName());
      storageMata.setDownloadStatus(DownloadStatus.DOWNLOADED);
      storageMata.setPathName(file.getAbsolutePath());
      return storageMata;
    }).filter(Objects::nonNull).collect(Collectors.toList());
    storageMataRepository.saveAll(storageMataList);
  }

  @Override
  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    this.applicationContext = (ConfigurableApplicationContext) applicationContext;
  }
  
  public static boolean isJap(String name) {
    return jap.matcher(name).matches();
  }
}
